﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using UtilZ.Dotnet.Ex.Base;
using UtilZ.Dotnet.Ex.Communication.Base;

namespace UtilZ.Dotnet.Ex.Communication.Net.Base
{
    /// <summary>
    /// TCP客户端初始化参数
    /// </summary>
    public class TcpClientInitPara : ClientInitParaAbs
    {
        /// <summary>
        /// Tcp连接建立类型
        /// </summary>
        private ConnectTypes _connectType;
        /// <summary>
        /// Tcp连接建立类型
        /// </summary>
        internal ConnectTypes ConnectType
        {
            get { return _connectType; }
        }

        private readonly Socket _client = null;
        /// <summary>
        /// 被动连接监听到的Socket
        /// </summary>
        public Socket Client
        {
            get { return _client; }
        }

        private readonly EndPoint _remoteEndPoint;
        /// <summary>
        /// 主动连接时,对方EndPoint
        /// </summary>
        public EndPoint RemoteEndPoint
        {
            get { return _remoteEndPoint; }
        }

        /// <summary>
        /// 主动连接时,本地指定终节点
        /// </summary>
        public EndPoint LocalEndPoint { get; set; } = null;

        /// <summary>
        /// 是否保活连接[true:保活连接;false;顺其自然]
        /// </summary>
        public bool KeepAlive { get; set; } = false;

        /// <summary>
        /// 离最后一次收发数据后,多长时间触发保活操作,单位秒
        /// </summary>
        public int KeepAliveTimeSeconds { get; set; } = 30;

        /// <summary>
        /// 触发保活操作间隔,单位秒
        /// </summary>
        public int KeepAliveIntervalSeconds { get; set; } = 1;

        /// <summary>
        /// 触发保活操作次数,即发送该次数未收到回应,认为tcp连接断开
        /// </summary>
        public int KeepRetryCount { get; set; } = 3;

        /// <summary>
        /// 接收线程名称
        /// </summary>
        public string ReceiveThreadName { get; set; }


        private int _receiveDataSize = 4096;
        /// <summary>
        /// 单次接收数据包大小
        /// </summary>
        public int ReceiveDataSize
        {
            get { return _receiveDataSize; }
            set
            {
                if (value <= 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(value), "单次接收数据包不能小于等于0");
                }

                if (value > this._bufferSize)
                {
                    throw new ArgumentOutOfRangeException(nameof(value), $"单次接收数据包大小不能大于解析缓存大小\"{this._bufferSize}\"");
                }

                _receiveDataSize = value;
            }
        }

        private int _bufferSize = 65536;
        /// <summary>
        /// 解析缓存大小，默认(65536=64k>tcp_max_mtu=65507)
        /// 注:
        /// 当缓存大小大于等于MTU_MAX2倍时,每次接收最大值为MTU_MAX
        /// 否则为缓存大小的1/4
        /// </summary>
        public int BufferSize
        {
            get { return _bufferSize; }
            set
            {
                //最小缓存4k
                if (value <= this._receiveDataSize)
                {
                    throw new ArgumentOutOfRangeException(nameof(value), $"解析缓存不能小于单次接收数据包大小\"{this._receiveDataSize}\"");
                }

                _bufferSize = value;
            }
        }

        private int _reconnectIntervalMilliseconds = 1000;
        /// <summary>
        /// 主动连接断开后，重连间隔,默认1000毫秒
        /// </summary>
        public int ReconnectIntervalMilliseconds
        {
            get { return _reconnectIntervalMilliseconds; }
            set
            {
                if (this._connectType == ConnectTypes.Active && value < 1)
                {
                    throw new ArgumentOutOfRangeException(nameof(value), "重连接间隔不能小于等1毫秒");
                }

                _reconnectIntervalMilliseconds = value;
            }
        }

        /// <summary>
        /// 最大接收空数据次数,超过该次数认为tcp连接意外断开,小于0表示无限制.默认为3
        /// </summary>
        public int MaxReceiveEmpyDataCount { get; set; } = 3;

        /// <summary>
        /// 安全证书
        /// </summary>
        public X509Certificate Certificate { get; set; } = null;

        /// <summary>
        /// 发送超时时长,单位:毫秒.大于0有效,小于等于0使用默认值
        /// </summary>
        public int SendMillisecondsTimeout { get; set; } = System.Threading.Timeout.Infinite;

        /// <summary>
        /// 发送超时时长,单位:毫秒.大于0有效,小于等于0使用默认值
        /// </summary>
        public int ReceiveMillisecondsTimeout { get; set; } = System.Threading.Timeout.Infinite;

        /// <summary>
        /// 同步接收数据连续发生错误时，最大重试次数，当超过此值时便会断开连接
        /// </summary>
        public int SynReceiveErrorMaxRepeatCount { get; set; } = 3;

        /// <summary>
        /// 监听到的Socket连接参数
        /// </summary>
        public AcceptSocketArgs SocketArgs { get; set; } = null;




        /// <summary>
        /// 构造函数-监听连接
        /// </summary>
        /// <param name="unpacker">分包器</param>
        /// <param name="client">监听到的Socket连接</param>
        /// <exception cref="ArgumentNullException">dataOutput或receiveEndPoint为null将抛出异常</exception>
        public TcpClientInitPara(IUnpacker unpacker, Socket client)
            : base(unpacker)
        {
            if (client == null)
            {
                throw new ArgumentNullException(nameof(client));
            }

            this._remoteEndPoint = client.RemoteEndPoint;
            this._client = client;
            this._connectType = ConnectTypes.Passive;
        }

        /// <summary>
        /// 构造函数-监听连接
        /// </summary>
        /// <param name="unpacker">分包器</param>
        /// <param name="args">监听到的Socket连接参数</param>
        /// <exception cref="ArgumentNullException">dataOutput或receiveEndPoint为null将抛出异常</exception>
        public TcpClientInitPara(IUnpacker unpacker, AcceptSocketArgs args)
            : base(unpacker)
        {
            if (args == null)
            {
                throw new ArgumentNullException(nameof(args));
            }

            this._remoteEndPoint = args.Client.RemoteEndPoint;
            this._client = args.Client;
            this._connectType = ConnectTypes.Passive;
        }

        /// <summary>
        /// 构造函数-主动连接
        /// </summary>
        /// <param name="unpacker">分包器</param>
        /// <param name="dstEndPoint">目标EndPoint</param>
        /// <exception cref="ArgumentNullException">dataOutput或receiveEndPoint为null将抛出异常</exception>
        public TcpClientInitPara(IUnpacker unpacker, EndPoint dstEndPoint)
            : base(unpacker)
        {
            if (dstEndPoint == null)
            {
                throw new ArgumentNullException(nameof(dstEndPoint));
            }

            this._remoteEndPoint = dstEndPoint;
            this._connectType = ConnectTypes.Active;
        }

    }
}
